#pragma once
#include <iostream>
#include <cstring>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include <unordered_map>
#include <utility>
#include "Log.hpp"
using std::cout;
using std::endl;
extern Log log;

using func_t = std::function<std::string(const std::string& , const std::string& , uint16_t )>;

class udp_server
{
private:
    int _sockfd;
    uint16_t _port = 8080;
    std::string _ip = "0.0.0.0";              
    std::unordered_map<std::string, struct sockaddr_in> _users;  //ip与套接字的映射表-->广播给所有连接

public:
    udp_server(uint16_t port = 8080):_port(port){}
    ~udp_server(){if(_sockfd > 0)close(_sockfd); }

    //建立连接  
    void Init();     

    //开始通信                                               
    void Run();                                               

    //----网络聊天室----

    //判断是否添加用户
    void AddUser(const struct sockaddr_in& client);

    //广播给所有用户
    void Broadcast(const std::string info, const std::string client_ip, uint16_t client_port);         

    std::string Handler(const std::string& info, const std::string client_ip, uint16_t client_port); 


};


//核心1.建立连接: 创建套接字, bind套接字, 
void udp_server::Init()
{
    //创建套接字
    _sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    if(_sockfd < 0){ log(Fatal, "socket create fail"); exit(1); }
    log(Info , "socket create success: %d", _sockfd);

    //bind套接字
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(_port);                  //主机转网络
    server.sin_addr.s_addr = inet_addr(_ip.c_str()); //主机转网络
    int check = bind(_sockfd, (struct sockaddr*)&server, sizeof(server));

    if(check < 0){ log(Fatal, "bind socket fail"); exit(2);}
    log(Info , "bind socket success: %d", _sockfd);
}


//核心2.开始通信: recvfrom, sendto
void udp_server::Run()
{
    char inbuffer[1024];
    struct sockaddr_in client;
    while(1)
    {
        //1.服务端接收数据
        socklen_t len = sizeof(client);
        ssize_t recv_nums = recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0 , (sockaddr*)&client, &len); //可能读取失败, 可以检测一下...


        uint16_t client_port = ntohs(client.sin_port);//网络转主机
        std::string client_ip = inet_ntoa(client.sin_addr);//网络转主机

        //2.服务端处理数据
        //添加用户
        AddUser(client);

        //广播信息
        std::string info = inbuffer;
        Broadcast(info, client_ip, client_port);
        
        //客户端退出
        if(std::string(inbuffer) == "quit")break;
        memset(inbuffer, 0 , sizeof(inbuffer));//清空
        
    }

    log(Info, "client quit");
}


 

//聊天室
std::string udp_server::Handler(const std::string& info, const std::string client_ip,  uint16_t client_port)
{
    cout << "[ " << client_ip << " : " << client_port << " ]# " << info << endl;
    std::string res = "server get a message : ";
    res += info;
    cout << res << endl;

    return res;
}

//添加用户
void udp_server::AddUser(const struct sockaddr_in& client)
{
    uint16_t client_port = ntohs(client.sin_port);//网络转主机
    std::string client_ip = inet_ntoa(client.sin_addr);//网络转主机

    auto iter = _users.find(client_ip);
    if(iter == _users.end())
    {
        _users.insert({client_ip, client});
        cout << "[ " << client_ip << " : " << client_port << " ]# " << "add success" << endl;
    }
}

//广播给所有用户
void udp_server::Broadcast(const std::string info, const std::string client_ip, uint16_t client_port)
{
    for(const auto& user : _users)
    {
        std::string message = "[ " + client_ip + " : " + std::to_string(client_port) + "]# " + info;
        socklen_t len = sizeof(user.second);
        sendto(_sockfd, message.c_str(), message.size(), 0, (sockaddr*)&user.second, len);
    }

}                           

































//std::string excuteCommand(std::string command);             //处理数据方式1: 执行对应的指令
////处理数据1: 执行对应的指令
// static bool isPass(const std::string &command)
// {   
//     bool pass = true;
//     auto pos = command.find("rm");
//     if(pos != std::string::npos) pass=false;
//     pos = command.find("mv");
//     if(pos != std::string::npos) pass=false;
//     pos = command.find("while");
//     if(pos != std::string::npos) pass=false;
//     pos = command.find("kill");
//     if(pos != std::string::npos) pass=false;
//     return pass;
// }

// std::string udp_server::excuteCommand(std::string command) // command就是一个命名
// {
//     // 1. 安全检查
//     if(!isPass(command)) return "you are bad man!";

//     // 2. 执行对应的指令
//     FILE *fp = popen(command.c_str(), "r");
//     if(fp == nullptr) return "None";
//     // 3. 获取结果了
//     char line[1024];
//     std::string result;
//     while(fgets(line, sizeof(line), fp) != NULL)
//     { 
//         result += line;
//     }
//     pclose(fp);

//     return result;
// }